//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	SecurityMatrixRow.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace Smart.Common.Security
{
	/// <summary>
	/// Security matrix row (define how to protect one kind of securable)
	/// </summary>
	[Localizable(false)]
	public class SecurityMatrixRow
	{
		/// <summary>
		/// Row name
		/// </summary>
		public string Name { get; set; }

		/// <summary>
		/// Inherit existing security assignment (left existing assignments)
		/// </summary>
		public bool Inherit { get; set; }

		/// <summary>
		/// Set security assignments to current scope only
		/// </summary>
		public bool CurrentScopeOnly { get; set; }

		/// <summary>
		/// Security assignments
		/// </summary>
		public Dictionary<string, SecurityAssignment> Assignments { get; set; }

		/// <summary>
		/// Security matrix row (define how to protect one kind of securable)
		/// </summary>
		public SecurityMatrixRow(string name, bool inherit)
			: this()
		{
			Name = name;
			Inherit = inherit;
		}

		/// <summary>
		/// Security matrix row (define how to protect one kind of securable)
		/// </summary>
		public SecurityMatrixRow()
		{
			Assignments = new Dictionary<string, SecurityAssignment>(StringComparer.OrdinalIgnoreCase);
		}

		/// <summary>
		/// Parse security matrix row <paramref name="row"/>
		/// </summary>
		/// <exception cref="FormatException">Row node should have attribute 'Name' specified!</exception>
		/// <exception cref="FormatException">Assignment node should have both attributes 'Principal' and 'AccessLevel' specified!</exception>
		public virtual void ParseXml(XElement row)
		{
			// ReSharper disable PossiblyMistakenUseOfParamsMethod
			var values = row.SafeGetAttributes(@"name", @"inherit", @"currentscopeonly");
			// ReSharper restore PossiblyMistakenUseOfParamsMethod

			Name = values[0].With(s => s.Trim());
			Inherit = values[1].With(s => s.Trim()).SToBool(false);
			CurrentScopeOnly = values[2].With(s => s.Trim()).SToBool(false);

			if (Name.IsNullOrEmpty())
				throw new FormatException("Row node should have attribute 'Name' specified!");

			foreach (var assignmentElement in row.Elements())
			{
				if (assignmentElement.NodeType != XmlNodeType.Element || !assignmentElement.Name.LocalName.EqIC(@"Assignment"))
					continue;

				string principal;
				string accessLevel;

				assignmentElement.SafeGetAttributes("principal", out principal, "accesslevel", out accessLevel);

				var assignment =
					new SecurityAssignment
					{
						Principal = principal.With(s => s.Trim()),
						AccessLevel = accessLevel.With(s => s.Trim()),
					};

				if (H.IsAnyNullOrEmpty(assignment.Principal, assignment.AccessLevel))
					throw new FormatException("Assignment node should have both attributes 'Principal' and 'AccessLevel' specified!");

				Assignments[assignment.Principal] = assignment;
			}
		}
	}
}